package middleware

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/net/gtrace"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"net/http"
	"server/internal/model/do"
	"server/internal/service"
)

type DefaultHandlerResponse struct {
	Code     int         `json:"code"    dc:"Error code"`
	Message  string      `json:"message" dc:"Error message"`
	Data     interface{} `json:"data"    dc:"Result data for certain request according API definition"`
	TraceID  string      `json:"traceID" dc:"TraceID"`
	TraceSQL interface{} //TODO
}

// exceptRoutes 排除以下路由，不需要记录请求日志
var exceptRoutes = g.Map{
	"/system/log/httpLogs":    true,
	"/system/log/fileContent": true,
}

// ResponseHandler is the default middleware handling handler response object and its error.
func ResponseHandler(r *ghttp.Request) {
	logData := do.SystemHttpLog{}
	logData.Route = r.Request.URL.Path
	logData.Method = r.Method
	logData.Ip = r.GetClientIp()
	logData.TraceId = gtrace.GetTraceID(r.GetCtx())
	logData.RequestAt = gtime.Now()

	// 获取所有请求参数
	allParamsJson, _ := json.Marshal(r.GetMap())
	logData.RequestData = allParamsJson

	r.Middleware.Next()

	//当存在错误的时候清空buffer，直接返回数据
	if err := r.GetError(); err != nil {
		r.SetError(r.GetError())
		r.Response.ClearBuffer()
	}

	// There's custom buffer content, it then exits current handler.
	if r.Response.BufferLength() > 0 {
		return
	}

	var (
		msg  string
		err  = r.GetError()
		res  = r.GetHandlerResponse()
		code = gerror.Code(err)
	)
	if err != nil {
		//系统抛出的错误，如请求参数验证失败、panic捕获、gerror.new(创建的错误)
		msg = err.Error()
		if code == gcode.CodeNil {
			code = gcode.CodeInternalError
		}

		//格式化部分已知错误
		switch {
		case errors.Is(err, sql.ErrNoRows):
			msg = fmt.Sprintf("数据不存在[%s]", sql.ErrNoRows)
		}

	} else {
		if r.Response.Status > 0 && r.Response.Status != http.StatusOK {
			//系统抛出的其他错误：如请求url未注册、操作文件时权限不够等
			msg = http.StatusText(r.Response.Status)
			switch r.Response.Status {
			case http.StatusNotFound:
				code = gcode.CodeNotFound // 65 Resource does not exist. 资源不存在
			case http.StatusForbidden:
				code = gcode.CodeNotAuthorized // 61 Not Authorized. 无权限：服务器理解请求客户端的请求，但是拒绝执行此请求
			default:
				code = gcode.CodeUnknown // 64 其他
			}
			// It creates error as it can be retrieved by other middlewares.
			r.SetError(gerror.NewCode(code, msg))
		} else {
			code = gcode.CodeOK
			msg = "请求成功"
		}
	}

	Response(r, code, msg, res)

	logData.ResponseCode = code.Code()
	logData.UserId = service.SystemLogin().GetAdminID(r.GetCtx())
	logData.ResponseData = res
	logData.ResponseAt = gtime.Now()
	logData.HttpStatusCode = r.Response.Status
	if _, ok := exceptRoutes[gconv.String(logData.Route)]; !ok {
		_, _ = service.SystemLog().Create(r.GetCtx(), logData)
	}
}

// Response 统一返回数据
func Response(r *ghttp.Request, code gcode.Code, msg string, data interface{}) {
	r.Response.WriteJson(&DefaultHandlerResponse{
		Code:    code.Code(),
		TraceID: gtrace.GetTraceID(r.GetCtx()),
		Message: msg,
		Data:    data,
	})
}
